#pragma once

#include "libzqutil/ustring.h"
#include "libzqutil/random.h"

#include "net/defines.h"
#include "curl/curl.h"
#include "client.h"

namespace libzq
{
	template<typename Protocol, typename Balancer>
	class ServerFinder
	{
	public:
		virtual void init(const string& url) = 0; // 初始化
		virtual shared_ptr<Client<Protocol>> find_server(const char* service, const char* method) = 0; // 查找可用的连接
	};

	template<typename Protocol, typename Balancer>
	class ZookeeperServerFinder :
		public ServerFinder<Protocol, Balancer>
	{
		SINGLETON(ZookeeperServerFinder)
	public:
		void init(const string& url) override;
		shared_ptr<Client<Protocol>> find_server(const char* service, const char* method) override;
	};

	template<typename Protocol, typename Balancer>
	inline void ZookeeperServerFinder<Protocol, Balancer>::init(const string& url)
	{
	}

	template<typename Protocol, typename Balancer>
	inline shared_ptr<Client<Protocol>> ZookeeperServerFinder<Protocol, Balancer>::find_server(const char* service, const char* method)
	{
		auto c = make_shared<Client<Protocol>>();
		c->connect("127.0.0.1", 43332);
		c->start_serve();
		return c;
	}


	size_t get_response(void * ptr, size_t size, size_t nmemb, void * userdata);

	template<typename Protocol, typename Balancer>
	class HttpServerFinder :
		public ServerFinder<Protocol, Balancer>
	{
		SINGLETON(HttpServerFinder)
	public:
		void init(const string& url) override;
		shared_ptr<Client<Protocol>> find_server(const char* service, const char* method) override;

	private:
		void find_service_hosts(const char* service, const char* method);
	private:
		co_mutex _mutex;
		string _url;
		map<string, bool> _service_task;
	};

	template<typename Protocol, typename Balancer>
	inline void HttpServerFinder<Protocol, Balancer>::init(const string& url)
	{
		_url = url;
	}

	template<typename Protocol, typename Balancer>
	inline shared_ptr<Client<Protocol>> HttpServerFinder<Protocol, Balancer>::find_server(const char* service, const char* method)
	{
		std::lock_guard<co_mutex> lock(_mutex);
		// 先尝试从服务均衡器中获取
		auto client = Balancer::instance().get(service);
		if (client != nullptr)
			return client;
		// 从服务发现 服务器获取
		find_service_hosts(service, method);
		return Balancer::instance().get(service);
	}

	template<typename Protocol, typename Balancer>
	inline void HttpServerFinder<Protocol, Balancer>::find_service_hosts(const char * service, const char * method)
	{
		CURL* curl = curl_easy_init();
		CURLcode CURLRes;
		string cfg;
		do
		{
			if (nullptr == curl)
			{
				LOGE("curl_easy_init error");
				break;
			}
			string url = format("%s?service=%s&method=%s&stamp=%d", _url, service, method, current_timestamp());
			curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
			curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
			curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, get_response);
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&cfg);

			CURLRes = curl_easy_perform(curl);
		} while (0);
		curl_easy_cleanup(curl);
		//LOGT("Current service node [%s] => [%s]", service, cfg);

		Balancer::instance().reset(cfg, service);
		if (_service_task.find(service) == _service_task.end())
		{
			LOGI("New task to sync service node of [ %s ]", service);
			_service_task[service] = true;
			CORE.run_until_stop(
				format("%s-finder", service),
				[=]()
			{
				HttpServerFinder<Protocol, Balancer>::find_service_hosts(service, method);
			},
				[=]()
			{
				Balancer::instance().reset("", service);
			}, 10);
		}
	}
}